#include <rtthread.h>
#include <board.h>
#include <rthw.h>
#include "rtdevice.h"
#include "drv_sys.h"
#include "nuc970_sys.h"
#include "nuc970_usbd.h"
#include "vcom_serial.h"

/*--------------------------------------------------------------------------*/
STR_VCOM_LINE_CODING gLineCoding = {115200, 0, 0, 8};   /* Baud rate : 115200    */
/* Stop bit     */
/* parity       */
/* data bits    */
uint16_t gCtrlSignal = 0;     /* BIT0: DTR(Data Terminal Ready) , BIT1: RTS(Request To Send) */

/*---------------------------------------------------------------------------------------------------------*/
/* Global variables                                                                                        */
/*---------------------------------------------------------------------------------------------------------*/
/* UART0 */
#ifdef __ICCARM__
#pragma data_alignment=4
uint8_t gUsbRxBuf[64] = {0};
#else
uint8_t gUsbRxBuf[64] __attribute__((aligned(4))) = {0};
#endif

uint32_t gu32RxSize = 0;
uint32_t gu32TxSize = 0;

volatile int8_t gi8BulkInReady = 0;
volatile int8_t gi8BulkOutReady = 0;
rt_sem_t bulkInReady_sem;
rt_sem_t bulkOutReady_sem;

extern S_USBD_INFO_T gVCOMInfo;
extern void USBD_IRQHandler(int vector, void *param);

void VCOM_TransferData(void)
{
    int32_t i;

    /* Process the Bulk out data when bulk out data is ready. */
    rt_sem_take(bulkOutReady_sem, RT_WAITING_FOREVER);

    for (i=0; i<gu32RxSize; i++)
        USBD->EP[EPA].ep.EPDAT_BYTE = gUsbRxBuf[i];
    USBD->EP[EPA].EPRSPCTL = USB_EP_RSPCTL_SHORTTXEN;    // packet end
    USBD->EP[EPA].EPTXCNT = gu32RxSize;
    USBD_ENABLE_EP_INT(EPA, USBD_EPINTEN_INTKIEN_Msk);

    rt_sem_take(bulkInReady_sem, RT_WAITING_FOREVER);
}

void vcom_thread(void *parameter)
{
    bulkInReady_sem = rt_sem_create("bulkin", 1, RT_IPC_FLAG_PRIO);
    bulkOutReady_sem = rt_sem_create("bulkout", 1, RT_IPC_FLAG_PRIO);

    USBD_Open(&gVCOMInfo, VCOM_ClassRequest, NULL);

    /* Endpoint configuration */
    VCOM_Init();

    /* Enable interrupt. */
    rt_hw_interrupt_install(USBD_IRQn, USBD_IRQHandler, (void *)(0), "vcom");
    rt_hw_interrupt_set_priority(USBD_IRQn, IRQ_LEVEL_1);
    rt_hw_interrupt_set_type(USBD_IRQn, HIGH_LEVEL_SENSITIVE);
    rt_hw_interrupt_umask(USBD_IRQn);

    while (1) {
        VCOM_TransferData();
    }
}

int vcom_task_init(void)
{
    rt_thread_t vcom_tid = rt_thread_create("vcom",
                           vcom_thread, RT_NULL,
                           1024,
                           0,
                           2);
    if (vcom_tid != RT_NULL)
        rt_thread_startup(vcom_tid);

    return 0;
}
INIT_APP_EXPORT(vcom_task_init);
